package com.gohi.core.dao.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;

import java.lang.reflect.ParameterizedType; 

import com.gohi.core.dao.IDAO;
import com.gohi.core.web.paging.PagingBean;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.hql.ast.QueryTranslatorImpl;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


public class BaseDAO<T,PK extends Serializable> 
	extends HibernateDaoSupport implements IDAO<T,PK> {
	
	protected Class<T> persistType;
	
	@SuppressWarnings("unchecked")  
	public BaseDAO() {
		// 获取持久化对象的类型  
        this.persistType = com.gohi.core.util.GenericsUtils.getSuperClassGenricType(getClass());
	}
	public Class<T> getPersistType() {
		return persistType;
	}


	protected JdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
   
	public T save(T entity) {
		this.getHibernateTemplate().saveOrUpdate(entity);
		return entity;
	}

	
	public T merge(T entity) {
		this.getHibernateTemplate().merge(entity);
		return entity;
	}

	@SuppressWarnings("unchecked")
	public T getByPK(T entity,PK id) {
		return (T)getHibernateTemplate().get(entity.getClass(),id);
	}

	
	public void remove(T entity,PK id) {
		getHibernateTemplate().delete(getByPK(entity,id));
	}

	
	public void evict(Object entity) {
		this.getHibernateTemplate().evict(entity);
	}

	public Long getTotalItems(String queryString, final Object[] values) {
		int orderByIndex = queryString.toUpperCase().indexOf(" ORDER BY ");

		if (orderByIndex != -1) {
			queryString = queryString.substring(0, orderByIndex);
		}

		QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(
				queryString, queryString, Collections.EMPTY_MAP,
				(SessionFactoryImplementor) getSessionFactory());
		queryTranslator.compile(Collections.EMPTY_MAP, false);
		final String sql = "select count(*) from ("
				+ queryTranslator.getSQLString() + ") tmp_count_t";

		Object reVal = getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				if (values != null) {
					for (int i = 0; i < values.length; i++) {
						query.setParameter(i, values[i]);
					}
				}
				return query.uniqueResult();
			}
		});
		return new Long(reVal.toString());
	}

	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				String hql = "from " + getPersistType().getName();
				Query query = session.createQuery(hql);
				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	
	public List<T> getAll(T entity, final PagingBean pb) {
		final String hql = "from " + getPersistType().getName();
		int totalItems = getTotalItems(hql, null).intValue();
		pb.setTotalItems(totalItems);
		return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(pb.getFirstResult()).setFetchSize(
						pb.getPageSize().intValue());
				query.setMaxResults(pb.getPageSize().intValue());
				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	
	public List<T> findByHql(final String hql, final Object[] objs) {
		return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (objs != null) {
					for (int i = 0; i < objs.length; i++) {
						query.setParameter(i, objs[i]);
					}
				}

				return query.list();
			}
		});
	}

	
	public List<T> findByHql(String hql, Object[] objs, PagingBean pb) {
		int totalItems = getTotalItems(hql, objs).intValue();
		pb.setTotalItems(totalItems);
		return findByHql(hql, objs, pb.getFirstResult(), pb.getPageSize().intValue());
	}

	@SuppressWarnings("unchecked")
	
	public List<T> findByHql(final String hql, final Object[] objs,
			final int firstResult, final int pageSize) {
		return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(firstResult).setMaxResults(pageSize);
				if (objs != null) {
					for (int i = 0; i < objs.length; i++) {
						query.setParameter(i, objs[i]);
					}
				}
				return query.list();
			}
		});
	}

	
	public Long getCount(String queryString, final Object[] values) {
		int orderByIndex = queryString.toUpperCase().indexOf(" ORDER BY ");

		if (orderByIndex != -1) {
			queryString = queryString.substring(0, orderByIndex);
		}

		QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(
				queryString, queryString, Collections.EMPTY_MAP,
				(SessionFactoryImplementor) getSessionFactory());
		queryTranslator.compile(Collections.EMPTY_MAP, false);
		final String sql = "select count(*) from ("
				+ queryTranslator.getSQLString() + ") tmp_count_t";

		Object reVal = getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(sql);
				if (values != null) {
					for (int i = 0; i < values.length; i++) {
						query.setParameter(i, values[i]);
					}
				}
				return query.uniqueResult();
			}
		});
		return new Long(reVal.toString());
	}
	



}
